﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

namespace LowLevelGraphics.Filter
{
    /// <summary>
    /// Registration modes
    /// </summary>
    public enum REGISTRATION_MODE
    {
        /// <summary>
        /// The image will be registrated of R, G and B channelled graylevel image
        /// </summary>
        RGB_THREE_CHANNEL,

        /// <summary>
        /// 
        /// </summary>
        MIX,
        /// <summary>
        /// 
        /// </summary>
        ADD,
        /// <summary>
        /// 
        /// </summary>
        NONE
    }

    //TODO: implement other moduses.
    /// <summary>
    /// This is used to combine several pics.
    /// </summary>
    public class ImageRegistration : BaseImageFilter
    {
        Bitmap m_BmpR = null;
        Bitmap m_BmpG = null;
        Bitmap m_BmpB = null;

        Bitmap m_Bmp1 = null;
        Bitmap m_Bmp2 = null;

        Size m_Step = Size.Empty;
        bool bWrap = false;
        Point m_ptOffset = Point.Empty;
        REGISTRATION_MODE M_REGISTRATION_MODE = REGISTRATION_MODE.RGB_THREE_CHANNEL;

        /// <summary>
        /// Initializes a new instance of the <see cref="ImageRegistration"/> class.
        /// </summary>
        public ImageRegistration()
        {
            this.M_REGISTRATION_MODE = REGISTRATION_MODE.NONE;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ImageRegistration"/> class.
        /// </summary>
        /// <param name="_bmp1">The _BMP1.</param>
        /// <param name="ptOffset">The pt offset.</param>
        /// <param name="step">The step.</param>
        /// <param name="_bWrap">if set to <c>true</c> [_b wrap].</param>
        public ImageRegistration(Bitmap _bmp1, Point ptOffset, Size step, bool _bWrap)
        {
            m_Bmp1 = _bmp1;
            m_Step = step;
            bWrap = _bWrap;
            m_ptOffset = ptOffset;

            this.M_REGISTRATION_MODE = REGISTRATION_MODE.MIX;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ImageRegistration"/> class.
        /// </summary>
        /// <param name="_imageRegistration">The _image registration.</param>
        internal ImageRegistration(ImageRegistration _imageRegistration)
        {
            this.M_REGISTRATION_MODE = _imageRegistration.M_REGISTRATION_MODE;
        }

        /// <summary>
        /// This constructor is used for gray level image combination.
        /// Use this if you got separated channels of an image and you like to recombine them together
        /// </summary>
        /// <param name="_bmpR">The _BMP R.</param>
        /// <param name="_bmpG">The _BMP G.</param>
        /// <param name="_bmpB">The _BMP B.</param>
        public ImageRegistration(Bitmap _bmpR, Bitmap _bmpG, Bitmap _bmpB )
        {
            m_BmpR = _bmpR;
            m_BmpG = _bmpG;
            m_BmpB = _bmpB;

            M_REGISTRATION_MODE = REGISTRATION_MODE.RGB_THREE_CHANNEL;
        }

        /// <summary>
        /// Execute this Filter
        /// A Debug Statement is written if a concrete Filter is called
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            UnsafeBitmap bitmap = _bitmap;

            int y = 0;
            int x = 0;

            int nHeight = bitmap.Height;
            int nWidth = bitmap.Width;

            switch (M_REGISTRATION_MODE)
            {
                case REGISTRATION_MODE.RGB_THREE_CHANNEL:
                    //Combine one pic of three different gray level pics (valid only for RGB separated channels)
                    UnsafeBitmap bmpR = new UnsafeBitmap(m_BmpR);
                    UnsafeBitmap bmpG = new UnsafeBitmap(m_BmpG);
                    UnsafeBitmap bmpB = new UnsafeBitmap(m_BmpB);
                    
                    if (m_BmpB.Size == m_BmpG.Size && m_BmpB.Size == m_BmpR.Size && _bitmap.Size == m_BmpR.Size)
                    {
                        for (y = 0; y < nHeight; y++)
                        {
                            for (x = 0; x < nWidth; x++)
                            {
                                bitmap.SetPixel(x, y,
                                    Color.FromArgb(
                                        bmpR.GetPixel(x, y).R,
                                        bmpG.GetPixel(x, y).G,
                                        bmpB.GetPixel(x, y).B
                                    ));
                            }
                        }
                    }
                    bmpR.Dispose();
                    bmpG.Dispose();
                    bmpB.Dispose();
                    break;

                //This is used to combine two pics.
                //Use offset to say where it starts
                //Use size to describe the steps. Size(2,2) -> every second pixel in x and y direction
                case REGISTRATION_MODE.MIX:
                    UnsafeBitmap bmp2 = new UnsafeBitmap(m_Bmp1);

                    for (y = m_ptOffset.Y; y < nHeight; y += m_Step.Height)
                    {
                        for (x = m_ptOffset.X; x < nWidth; x += m_Step.Width)
                        {
                            bitmap.SetPixel(x, y, bmp2.GetPixel(x, y));
                        }
                    }
                    bmp2.Dispose();
                    break;

                case REGISTRATION_MODE.ADD:
                    break;
            }

            return _bitmap;
        }

        /// <summary>
        /// This is used to clone a filter, each filter must implement it's own clone functionality
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new ImageRegistration(this);
        }
    }
}
